<script setup lang="ts">
import { computed, ref, watch } from "vue";
import type { OptionType, TabType, UserType, OrgType } from "./types";
import { DEFAULT_TAB, DEFAULT_TITLE_MAP, SelectTypeEnum } from "./constants";
import usePost from "@/hooks/usePost";
import { OptionTagTypeEnum } from "./constants";
import EmptyImage from "@/assets/images/empty-image.png";

const { runAsync: queryOrganization, loading } = usePost("POST", "/auth-api/orgResource/list");
/** 获取全部 */
const { runAsync: queryAllOrganization, loading: getAllLoading } = usePost("POST", "/auth-api/orgResource/listAll");
const props = withDefaults(
		defineProps<{
			/** 是否显示 */
			modelValue: boolean;
			title?: string;
			type?: SelectTypeEnum;
			defaultSelected?: string[];
			// 默认单选
			multiSelect?: boolean;
		}>(),
		{
			type: SelectTypeEnum.Hybrid,
			multiSelect: false
		}
	),
	emits = defineEmits<{
		(e: "update:modelValue", value: boolean): void;
		(e: "confirm", selectCodes: string[], selectedOptions: OptionType[]): void;
	}>();

const searchKey = ref(""),
	tabActive = ref("all"),
	tabList = ref<TabType[]>([...DEFAULT_TAB]),
	optionsData = ref<OptionType[]>([]),
	tabRef = ref(),
	selectCodes = ref<string[]>([]),
	selectOptions = ref<OptionType[]>([]),
	/** 是否展示已选择 */
	showSelectedArea = ref(false),
	/** 全部组织机构数据 */
	allOptionsData = ref<OptionType[]>([]);

watch(
	() => props.modelValue,
	() => {
		if (props.modelValue) {
			getOrganization();
		}
	}
);
/** 默认标题 */
const defaultTitle = computed(() => {
	return props.title || DEFAULT_TITLE_MAP[props.type];
});

const handleClose = () => {
	emits("update:modelValue", false);
};

const popupClosed = () => {
	searchKey.value = "";
	selectCodes.value = [];
	selectOptions.value = [];
	tabList.value = [...DEFAULT_TAB];
	tabActive.value = "all";
	showSelectedArea.value = false;
};

const tabChange = async (name: string) => {
	// 删除当前tab后面的tab
	const index = tabList.value.findIndex(item => item.key === name);
	if (index !== -1) {
		tabList.value.splice(index + 1);
	}
	await getOrganization({
		orgCode: name === "all" ? undefined : name
	});
};

/** 获取组织机构信息 */
const getOrganization = async (params = {}) => {
	const { data } = await queryOrganization({
		type: "hybrid",
		...params
	});

	optionsData.value = props.type === SelectTypeEnum.Org ? data.filter((s: OptionType) => s.tag === OptionTagTypeEnum.Org) : data;
};

/** 获取全部组织机构信息 */
const getAllOrganization = async () => {
	const { data } = await queryAllOrganization({
		type: "hybrid"
	});
	allOptionsData.value = data;
};

const clickOption = (item: OptionType) => {
	const isOrg = item.tag === OptionTagTypeEnum.Org,
		isUser = item.tag === OptionTagTypeEnum.User;
	if (props.type === SelectTypeEnum.User && isOrg) {
		return;
	}
	if ((isOrg && selectCodes.value.includes(item.orgCode)) || (isUser && selectCodes.value.includes(item.userName))) {
		removeSelect(item);
	} else {
		if (props.multiSelect) {
			selectCodes.value.push(isUser ? item.userName : item.orgCode);
			selectOptions.value.push(item);
		} else {
			selectCodes.value = isUser ? [item.userName] : [item.orgCode];
			selectOptions.value = [item];
		}
	}
};

const handleConfirm = () => {
	emits("confirm", selectCodes.value, selectOptions.value);
	handleClose();
};

const removeSelect = (select: OptionType) => {
	const isUser = select.tag === OptionTagTypeEnum.User;
	selectCodes.value = selectCodes.value.filter(code => (isUser ? code !== select.userName : code !== select.orgCode));
	selectOptions.value = selectOptions.value.filter(option =>
		isUser ? (option as UserType).userName !== select.userName : (option as OrgType).orgCode !== select.orgCode
	);
};

const timer = ref<any>();
const searchInput = (value: string) => {
	if (timer.value) {
		clearTimeout(timer.value);
		timer.value = null;
	}
	timer.value = setTimeout(() => {
		showSelectedArea.value = false;
		tabActive.value = "all";
		tabList.value.splice(1);
		getOrganization({
			name: value ? value.trim() : undefined,
			type: props.type
		});
		clearTimeout(timer.value);
		timer.value = null;
	}, 300);
};

/** 打开下级 */
const toJunior = (item: OrgType) => {
	if (item.hasChild || item.hasUser) {
		tabList.value.push({
			key: item.orgCode,
			name: item.orgName
		});
		requestAnimationFrame(() => {
			tabActive.value = item.orgCode;
			tabChange(item.orgCode);
		});
	}
};

const popupOpen = async () => {
	if (props.defaultSelected?.length) {
		allOptionsData.value.length === 0 && (await getAllOrganization());
		selectCodes.value = props.defaultSelected;
		selectOptions.value = allOptionsData.value.filter((op: OptionType) => {
			return props.defaultSelected?.includes(op.tag === OptionTagTypeEnum.User ? op.userName : op.orgCode);
		});
	}
};

defineExpose({
	selectCodes,
	selectOptions,
	removeSelect
});
</script>

<template>
	<van-popup
		v-model:show="props.modelValue"
		round
		position="bottom"
		safe-area-inset-bottom
		@open="popupOpen"
		@closed="popupClosed"
	>
		<div class="cascader">
			<header class="header">
				<span class="btn cancel" @click="handleClose">取消</span>
				<span class="tit"> {{ defaultTitle }}</span>
				<span class="btn confirm" @click="handleConfirm">确认</span>
			</header>
			<div class="search">
				<van-search placeholder="请输入关键字" v-model="searchKey" clear-trigger="always" @update:model-value="searchInput" />
			</div>
			<div class="select-num" v-loading="getAllLoading">
				<span>已选择：{{ selectCodes.length }}</span>
				<span v-if="selectCodes.length || showSelectedArea" class="btn view-btn" @click="showSelectedArea = !showSelectedArea">{{
					showSelectedArea ? "返回" : "查看已选择"
				}}</span>
			</div>
			<van-tabs v-show="!showSelectedArea" v-model:active="tabActive" color="#1E8FA0" @change="tabChange" shrink ref="tabRef">
				<template v-for="item in tabList" :key="item.key">
					<van-tab :name="item.key" :title="item.name"></van-tab>
				</template>
			</van-tabs>
			<div v-show="!showSelectedArea" class="options" v-loading="loading">
				<div
					:class="[
						'option',
						((item.tag === OptionTagTypeEnum.User && selectCodes.includes(item.userName)) ||
							(item.tag === OptionTagTypeEnum.Org && selectCodes.includes(item.orgCode))) &&
							'active-option',
						((type === SelectTypeEnum.User && item.tag !== OptionTagTypeEnum.User) ||
							(type === SelectTypeEnum.Org && item.tag !== OptionTagTypeEnum.Org)) &&
							'disabled-option'
					]"
					v-for="item in optionsData"
					:key="item.id"
					@click="clickOption(item)"
				>
					<van-icon :name="item.tag === OptionTagTypeEnum.User ? 'user-o' : 'cluster-o'" />
					<span class="name">{{ item.tag === OptionTagTypeEnum.User ? item.realName : item.orgName }}</span>
					<div class="more-icon">
						<van-icon
							v-if="
								(item.tag === OptionTagTypeEnum.User && selectCodes.includes(item.userName)) ||
								(item.tag === OptionTagTypeEnum.Org && selectCodes.includes(item.orgCode))
							"
							name="success"
							style="margin-right: 5px"
							color="#1e8fa0"
						/>
						<van-icon
							v-if="
								item.tag === OptionTagTypeEnum.Org &&
								((type !== SelectTypeEnum.Org && (item.hasChild || item.hasUser)) ||
									(type === SelectTypeEnum.Org && item.hasChild))
							"
							name="ellipsis"
							class="ellipsis active-icon"
							@click.stop="toJunior(item)"
						/>
					</div>
				</div>
				<van-empty
					v-if="!showSelectedArea && !optionsData.length"
					:image="EmptyImage"
					image-size="50"
					description="暂无数据"
				></van-empty>
			</div>
			<div v-show="showSelectedArea" class="select-area">
				<div class="option" v-for="item in selectOptions" :key="item.id">
					<van-icon :name="item.tag === OptionTagTypeEnum.User ? 'user-o' : 'cluster-o'" />
					<span class="name">{{ item.tag === OptionTagTypeEnum.User ? item.realName : item.orgName }}</span>
					<div class="more-icon" @click="removeSelect(item)"><van-icon name="cross" class="active-icon" /></div>
				</div>
			</div>
		</div>
	</van-popup>
</template>

<style scoped lang="less">
.cascader {
	width: 100%;
	height: 80vh;
	.header {
		width: 100%;
		padding: 10px;
		font-size: 18px;
		display: flex;
		align-items: center;
		justify-content: space-between;
		.tit {
			width: 70vw;
			text-align: center;
			overflow: hidden;
			text-overflow: ellipsis;
			white-space: nowrap;
		}
	}
	.select-num {
		padding: 5px 10px;
		font-size: 14px;
		display: flex;
		justify-content: space-between;
		height: 26px;
		.view-btn {
			margin-left: 20px;
			color: #1e8fa0;
		}
	}
	.options,
	.select-area {
		width: 100%;
		height: calc(100% - 44px - 54px - 42px - 26px - 10px);
		overflow-x: hidden;
		overflow-y: auto;
		margin-top: 10px;
		&::-webkit-scrollbar {
			width: 0;
			height: 0;
			display: none;
		}
		.option {
			width: 100%;
			padding: 10px 50px 10px 10px;
			font-size: 14px;
			position: relative;
			display: flex;
			align-items: center;
			.name {
				margin-left: 5px;
				width: 100%;
				overflow: hidden;
				text-overflow: ellipsis;
				white-space: nowrap;
				display: inline-block;
			}
			.more-icon {
				position: absolute;
				right: 10px;
				top: 50%;
				transform: translateY(-50%);
				display: flex;
				justify-content: flex-end;
				align-items: center;
				.active-icon {
					opacity: 0.6;
				}
				.ellipsis {
					color: var(--color-text) !important;
				}
			}
			&:active {
				background-color: #f5f5f5;
			}
		}
	}
	.select-area {
		height: calc(100% - 54px - 42px - 26px - 10px);
	}
	.active-option {
		color: #1e8fa0;
	}
	.disabled-option {
		color: var(--van-text-color-3);
		&:active {
			background-color: unset !important;
		}
	}
	.btn {
		font-size: 15px;
		&.confirm {
			color: #1e8fa0;
		}
		&:active {
			opacity: 0.6;
		}
	}
}
</style>
